package com.yixun.qfbao.util;

import com.alibaba.druid.util.StringUtils;
import com.yixun.qfbao.mapper.SubscriptionMapper;
import com.yixun.qfbao.model.Subscription;
import com.yixun.qfbao.model.dto.SubscriptionDto;
import com.yixun.qfbao.model.enums.DelFlagEnum;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Component
public class WeixinCommon {
	
	@Autowired
	SubscriptionMapper subscriptionMapper;
	
	private static Logger logger= LoggerFactory.getLogger(WeixinCommon.class);
	public static String getSignature(String jsapi_ticket, String timestamp,
			String nonce, String jsurl) throws IOException {
		/****
		 * 对 jsapi_ticket、 timestamp 和 nonce 按字典排序 对所有待签名参数按照字段名的 ASCII
		 * 码从小到大排序（字典序）后，使用 URL 键值对的格式（即key1=value1&key2=value2…）拼接成字符串
		 * string1。这里需要注意的是所有参数名均为小写字符。 接下来对 string1 作 sha1 加密，字段名和字段值都采用原始值，不进行
		 * URL 转义。即 signature=sha1(string1)。
		 * **如果没有按照生成的key1=value&key2=value拼接的话会报错
		 */
		String[] paramArr = new String[] { "jsapi_ticket=" + jsapi_ticket,
				"timestamp=" + timestamp, "noncestr=" + nonce, "url=" + jsurl };
		Arrays.sort(paramArr);
		// 将排序后的结果拼接成一个字符串
		String content = paramArr[0].concat("&" + paramArr[1])
				.concat("&" + paramArr[2]).concat("&" + paramArr[3]);
		System.out.println("拼接之后的content为:" + content);
		String gensignature = null;
		try {
			MessageDigest md = MessageDigest.getInstance("SHA-1");
			// 对拼接后的字符串进行 sha1 加密
			byte[] digest = md.digest(content.toString().getBytes());
			gensignature = byteToStr(digest);
		} catch (NoSuchAlgorithmException e) {
			logger.error("getSignature ticket: {}, error: {}", "," + "jsapi_ticket: "+jsapi_ticket	+ ","
					+ "timestamp: "+timestamp + "," + "nonce: "+nonce+ "," + "jsurl: "+jsurl, e);
		}
		// 将 sha1 加密后的字符串与 signature 进行对比
		if (gensignature != null) {
			return gensignature;// 返回signature
		} else {
			return "false";
		}
		// return (String) (ciphertext != null ? ciphertext: false);
	}

	/**
	 * 将字节数组转换为十六进制字符串
	 *
	 * @param byteArray
	 * @return
	 */
	private static String byteToStr(byte[] byteArray) {
		String strDigest = "";
		for (int i = 0; i < byteArray.length; i++) {
			strDigest += byteToHexStr(byteArray[i]);
		}
		return strDigest;
	}

	/**
	 * 将字节转换为十六进制字符串
	 *
	 * @param mByte
	 * @return
	 */
	private static String byteToHexStr(byte mByte) {
		char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A',
				'B', 'C', 'D', 'E', 'F' };
		char[] tempArr = new char[2];
		tempArr[0] = Digit[(mByte >>> 4) & 0X0F];
		tempArr[1] = Digit[mByte & 0X0F];
		String s = new String(tempArr);
		return s;
	}
	
	/**
	 * 根据token,timestamp,nonce校验参数是否合法
	 * @param signature
	 * @param token
	 * @param timestamp
	 * @param nonce
	 * @return
	 */
	public static boolean checkSignature(String signature, String token, String timestamp, String nonce) {
		if(StringUtils.isEmpty(signature)) {
			return false;
		}
		return signature.equalsIgnoreCase(getSignature(token, timestamp, nonce));
	}
	
	/**
	 * 根据token，timestamp，nonce 获取Signature
	 * @param token
	 * @param timestamp
	 * @param nonce
	 * @return
	 */
	public static String getSignature(String token, String timestamp, String nonce) {
		String checktext = null;
		String paramArr[] = new String[] {token, timestamp, nonce};
		Arrays.sort(paramArr);
		String content = paramArr[0].concat(paramArr[1]).concat(paramArr[2]);
		try {
            MessageDigest md = MessageDigest.getInstance("SHA-1");
            //对接后的字符串进行sha1加密
            byte[] digest = md.digest(content.toString().getBytes());
            checktext = byteToStr(digest);
            return checktext;
        } catch (NoSuchAlgorithmException e) {
        	logger.error(e.getMessage(), e);
        }
		return null;
	}
	
	/**
	 * 通过request 获取微信传递过来的消息
	 * @return
	 */
	public static String streamToString(HttpServletRequest request) {
		try {
			BufferedReader reader = new BufferedReader(new InputStreamReader(request.getInputStream()));
			StringBuilder sb = new StringBuilder();
			String line;
			while ((line = reader.readLine()) != null) {
				sb.append(line);
			}
			return sb.toString();
		} catch (IOException e) {
			logger.error(e.getMessage(), e);
		}
		return "";
		
	}
	
	public static void main(String[] args) {
		String timestamp = "1600682214";
		String nonce = "1190997748";
		String signature = "2579f991832f1e3d13c6c14865202fd424b3523f";
		System.out.println(WeixinCommon.checkSignature(signature, "channel", timestamp, nonce));
	}

	/**
	 * 把单层的xml转换成map
	 * @param xmlContent
	 * @return
	 */
	public static Map<String, String> xmlToMap(String xmlContent) {
		Map<String, String> resMap = new HashMap<>();
		Document document;
		try {
			document = DocumentHelper.parseText(xmlContent);
		} catch (DocumentException e1) {
			return null;
		}
        // 得到xml根元素  
        Element root = document.getRootElement();  
        // 得到根元素的所有子节点  
        @SuppressWarnings("unchecked")
		List<Element> elementList = root.elements();  
  
        // 遍历所有子节点  
        for (Element e : elementList)  
        	resMap.put(e.getName(), e.getText());  
  
  
        return resMap;
	}
	
	/**
	 * 根据渠道ID，公司，获取对应的appId和appSecret
	 * @param systemId
	 * @param companyUuid
	 * @return
	 */
	public String getRealAppId(String systemId, String companyUuid) {
    	if(StringUtils.isEmpty(systemId)) {
    		return null;
    	}
    	if(StringUtils.isEmpty(companyUuid)) {
    		return null;
    	}
//    	String appIdKey = "APPID_" + companyUuid + "_" + systemId;
//        Object obj = RedisUtil.get(appIdKey);
//        if(obj != null) {
//            return obj.toString();
//        }
    	SubscriptionDto subscriptionDto = new SubscriptionDto();
    	subscriptionDto.setCompanyUuid(companyUuid);
    	subscriptionDto.setSystemId(systemId);
    	subscriptionDto.setDelFlag(DelFlagEnum.UNDEL.getNo());
    	List<Subscription> subscriptionList = subscriptionMapper.selectListByDto(subscriptionDto);
    	if(CollectionUtils.isEmpty(subscriptionList)) {
    		return null;
    	}
    	String appId = subscriptionList.get(0).getAppId();
//    	RedisUtil.setEx(appIdKey, appId, 14400, TimeUnit.SECONDS);
    	return appId;
    }
}
